package edu.uj.petri.model;

import java.io.Serializable;
import edu.uj.petri.commands.Restorable;
import edu.uj.util.Observed;
import edu.uj.util.ObserverList;
import edu.uj.petri.commands.Memento;
import edu.uj.util.Observer;

/**
 * abstract base class for various kinds of arcs.
 * @author Piotrek
 */
public abstract class Arc implements Serializable, Restorable, Observed {
    private ArcImpl impl;

    protected ObserverList observerList;

    /** Observed event code */
    public static final int REVERSED = 8566;

    Arc(Node from, Node to, ArcImpl impl) {
        this.impl = impl;
        observerList = new ObserverList();
        
        impl.setFrom(from);
        impl.setTo(to);
    }

    /**
     * given begin, returns end; given end, returns begin; otherwise throws exception
     */
    public Node getAnotherEnd(Node node) {
        if (node.equals(impl.getFrom()))
            return impl.getTo();
        if (node.equals(impl.getTo()))
            return impl.getFrom();
        throw new IllegalArgumentException("node is neither arc begin nor arc end");
    }

    /**
     * tries to reverse begin with end; throws exception if this is not possible
     */
    public void reverse() {
        impl.reverse();
        observerList.notifyAllSubscribers(REVERSED);
    }

    /**
     * returns fire when this arc does not prevent in firing a transition it is
     * connected with
     */
    public abstract boolean canBeFired();

    /**
     * performs firing actions limited to this arc
     */
    public abstract void fire();
    
    public Node getFrom() {
        return impl.getFrom();
    }
    
    public Node getTo() {
        return impl.getTo();
    }
    

    /**
     * stores internal state in a memento
     */
    public Memento getMemento() {
        return impl.getMemento();
    }

    /**
     * restores internal state of object to state stored in the memento
     */
    public void applyMemento(Memento memento) {
        impl.applyMemento(memento);
    }

    public void subscribe(Observer o) {
        observerList.subscribe(o);
    }

    public void unsubscribe(Observer o) {
        observerList.unsubscribe(o);
    }
}
